package com.jackstraw.jack_base.datasource.elasticsearch.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import com.jackstraw.jack_base.datasource.elasticsearch.entity.bean.ElasticSearchRouting;
import com.jackstraw.jack_base.datasource.elasticsearch.entity.bean.ElasticSearchTemplate;
import com.jackstraw.jack_base.datasource.elasticsearch.entity.ElasticSearchBaseEntity;
import com.jackstraw.jack_base.datasource.elasticsearch.repository.ElasticsearchRepository;
import com.jackstraw.jack_base.datasource.elasticsearch.service.ElasticSearchService;
import com.jackstraw.jack_base.util.entity.BaseEntity;
import org.apache.commons.collections4.IterableUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import java.lang.reflect.Constructor;
import java.util.List;


/**
 * @param <T>
 * @param <ER>
 */
public abstract class DefaultElasticSearchServiceImpl<
        ESS extends ElasticSearchService<T, ER>,
        T extends ElasticSearchBaseEntity<T>,
        ER extends ElasticsearchRepository<T>>
        extends BaseEntity<ESS>
        implements ElasticSearchService<T, ER> {

    /**
     * es路由类
     */
    private ElasticSearchRouting elasticSearchRouting;

    public DefaultElasticSearchServiceImpl(ElasticSearchRouting elasticSearchRouting) {
        this.elasticSearchRouting = elasticSearchRouting;
    }

    private ER elasticsearchRepository;


    protected ER getElasticsearchRepository() {
        return this.elasticsearchRepository;
    }

    @Override
    public ElasticsearchClient elasticsearchClient() {
        ElasticSearchTemplate elasticSearchTemplate = getElasticsearchRepository().getElasticSearchRouting().determineTargetEntity();
        return elasticSearchTemplate.getElasticsearchClient();
    }

    @Override
    public ElasticsearchAsyncClient elasticsearchAsyncClient() {
        ElasticSearchTemplate elasticSearchTemplate = getElasticsearchRepository().getElasticSearchRouting().determineTargetEntity();
        return elasticSearchTemplate.getElasticsearchAsyncClient();
    }

    @Override
    public Boolean createIndex() {
        if (this.getElasticsearchRepository().existsIndex()) {
            return true;
        }
        return this.getElasticsearchRepository().createIndex();

    }

    @Override
    public Boolean existsIndex() {
        return this.getElasticsearchRepository().existsIndex();
    }

    @Override
    public Boolean deleteIndex() {
        return this.getElasticsearchRepository().deleteIndex();
    }

    @Override
    public T save(T t) {
        return this.getElasticsearchRepository().save(t);
    }

    @Override
    public List<T> saveAll(List<T> ts) {
        return IterableUtils.toList(this.getElasticsearchRepository().saveAll(ts));
    }

    @Override
    public T update(T t) {
        return this.getElasticsearchRepository().update(t);
    }

    @Override
    public List<T> updateAll(List<T> ts) {
        return IterableUtils.toList(this.getElasticsearchRepository().updateAll(ts));
    }

    @Override
    public List<T> findAll() {
        return this.getElasticsearchRepository().findAll();
    }

    @Override
    public List<T> findAll(Sort sort) {
        return this.getElasticsearchRepository().findAll(sort);
    }

    @Override
    public Page<T> findAll(Pageable pageable) {
        return this.getElasticsearchRepository().findAll(pageable);
    }

    @Override
    public List<T> findAllById(Iterable<String> ids) {
        return IterableUtils.toList(this.getElasticsearchRepository().findAllById(ids));
    }

    @Override
    public T findById(String id) {
        return this.getElasticsearchRepository().findById(id).get();
    }

    @Override
    public void delete(T entity) {
        this.getElasticsearchRepository().delete(entity);
    }

    @Override
    public void deleteAll() {
        this.getElasticsearchRepository().deleteAll();
    }

    @Override
    public void deleteById(String id) {
        this.getElasticsearchRepository().deleteById(id);
    }

    @Override
    public void deleteAllById(Iterable<String> ids) {
        this.getElasticsearchRepository().deleteAllById(ids);
    }

    @Override
    public void deleteAll(Iterable<? extends T> entities) {
        this.getElasticsearchRepository().deleteAll(entities);

    }

    @Override
    public Boolean existsById(String id) {
        return this.getElasticsearchRepository().existsById(id);
    }

    @Override
    public Long count() {
        return this.getElasticsearchRepository().count();
    }

    @Override
    public Page<T> searchSimilar(T entity, String[] fields, Pageable pageable) {
        return this.getElasticsearchRepository().searchSimilar(entity, fields, pageable);
    }

    @Override
    public List<T> search(T entity) {
        return this.getElasticsearchRepository().search(entity);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //获取实体类型
        Class tClass = this.getEntityClass(1);

        //获取elasticsearchRepository类型
        Class erClass = this.getEntityClass(2);

        //通过反射创建elasticsearchRepository
        Constructor constructor = erClass.getConstructor(this.elasticSearchRouting.getClass(), tClass.getClass());
        ER elasticsearchRepository = (ER) constructor.newInstance(this.elasticSearchRouting, tClass);
        this.elasticsearchRepository = elasticsearchRepository;
    }
}
